﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime;
using System.Runtime.Caching;
using Think.Extend;

namespace XQT.Cache
{
    /// <summary>
    /// .Net MemoryCache使用
    /// </summary>
    internal class XCache
    {
        private MemoryCache cache = null;

        public XCache(string name)
        {
            cache = new MemoryCache(name);
        }

        private CacheItem CreateItem(string key, object value)
        {
            var ci = new CacheItem(key, value);
            return ci;
        }

        public void Set(string key, object value)
        {
            cache.Set(CreateItem(key, value), new CacheItemPolicy());
        }

        public void Set(string key, object value, int seconds)
        {
            cache.Set(CreateItem(key, value), new CacheItemPolicy() { AbsoluteExpiration = DateTime.Now.AddSeconds(seconds) });
        }

        public void Set(string key, object value, CacheItemPolicy cacheItemPolicy)
        {
            cache.Set(CreateItem(key, value), cacheItemPolicy);
        }

        public object Get(string key)
        {
            return cache[key];
        }

        public bool Contains(string key)
        {
            return cache.Contains(key);
        }

        public object Remove(string key)
        {
            return cache.Remove(key);
        }

        public T Get<T>(string key)
        {
            return Get(key).ChangeType<T>();
        }

        private XCache Locate(string[] keys, bool autoset = true)
        {
            var r = this;
            for (int i = 0; i < keys.Length - 1; i++)
            {
                var ck = keys[i];
                if (r.Contains(ck))
                {
                    r = r.Get<XCache>(ck);
                }
                else if (autoset)
                {
                    var v = new XCache(ck);
                    r.Set(ck, v);
                    r = v;
                }
                else
                {
                    //throw new Exception("Key:{0}".Fmt(ck));
                }
            }
            return r;
        }


        /// <summary>
        /// 多级缓存设置
        /// </summary>
        /// <param name="args">至少两个，最后一个参数为缓存值 </param>
        public void SetWith(params object[] args)
        {
            if (args == null || args.Length < 2)
            {
                throw new Exception(string.Format("SetWith 参数至少两个"));
            }
            var v = args[args.Length - 1];
            var key = args[args.Length - 2];
            var keys = args.Where((c, i) => i < (args.Length - 2)).Select(c => c.ToString()).ToArray();
            this.Locate(keys).Set(args[args.Length - 2].ToString(), v);
        }

        /// <summary>
        /// 层级获取
        /// </summary>
        /// <param name="allkeys">层级路径 </param>
        /// <returns></returns>
        /// <remarks >
        /// GetWith()=>all cache Dictionary《 string,object》
        /// GetWith("level1","level2","level3"。。。。)
        /// </remarks>
        public object GetWith(params object[] allkeys)
        {
            if (allkeys == null || allkeys.Length == 0)
            {
                return this.cache.ToDictionary((kv) => kv.Key);
            }
            var key = allkeys[allkeys.Length - 1].ToString();
            var keys = allkeys.Where((c, i) => i < (allkeys.Length - 1)).Select(c => c.ToString()).ToArray();
            return this.Locate(keys, false).Get(key);
        }

        public bool ContainsWith(params object[] keys)
        {
            var r = this;
            for (int i = 0; i < keys.Length - 1; i++)
            {
                var ck = keys[i].ToString();
                if (r.Contains(ck))
                {
                    r = r.Get<XCache>(ck);
                }
                else
                {
                    return false;
                }
            }
            return true;
        }

        public object RemoveWith(params object[] keys)
        {
            var k = keys[keys.Length - 1].ToString();
            var ckeys = keys.Where((c, i) => i < (keys.Length - 1)).Select(c => c.ToString()).ToArray();
            var lcache = this.Locate(ckeys, false);
            return lcache.Remove(k);
        }

    }

}
